const PENDING = "pending"; // 等待
const FUIFILLED = "fulfilled"; // 成功
const REJECTED = "rejected"; // 失败

/**
 * 手写MyPromise类
 */
class MyPromise {
  #state = PENDING; // 私有状态
  #result = undefined; // 私有结果
  #handlers = []; // 存储成功回调、失败回调、resolve、reject等

  /**
   * 构造函数
   * @param {Function} executor 构造器
   * @returns {void} void
   */
  constructor(executor) {
    const resolve = data => {
      this.#changeState(FUIFILLED, data);
    };
    const reject = reason => {
      this.#changeState(REJECTED, reason);
    };

    try {
      executor(resolve, reject);
    } catch (error) {
      reject(error);
    }
  }

  /**
   * 状态改变函数
   * @param {string} state 内部状态
   * @param {any} result 内部结果
   * @returns {void} void
   */
  #changeState(state, result) {
    if (this.#state !== PENDING) return;
    this.#state = state;
    this.#result = result;
    this.#run();
  }

  /**
   * 是否是一个promise
   * @param {any} value 参数
   * @returns {boolean} boolean
   */
  #isPromiseLike(value) {
    if (value !== null && (typeof value === "object" || typeof value === "function")) {
      return typeof value.then === "function";
    }
    return false;
  }

  /**
   * 微任务
   * @param {Function} func 回调函数
   * @returns {void} void
   */
  #runMicrotask(func) {
    // 区分环境Node和Window
    if (typeof process === "object" && typeof process.nextTick === "function") {
      process.nextTick(func);
    } else if (typeof MutationObserver === "function") {
      const ob = new MutationObserver();
      const textNode = document.createTextNode("1");
      ob.observe(textNode, { characterData: true });
      textNode.data = "2";
    } else {
      setTimeout(func, 0);
    }
  }

  /**
   * 抽取公共函数，遵循DRY原则
   * @param {Function} callback onFulfilled&onRejected回调函数
   * @param {Function} resolve 成功回调
   * @param {Function} reject 失败回调
   * @returns {void} void
   */
  #runOne(callback, resolve, reject) {
    this.#runMicrotask(() => {
      if (typeof callback !== "function") {
        const settled = this.#state === FUIFILLED ? resolve : reject;
        settled(this.#result);
        return;
      }
      try {
        const data = callback(this.#result);
        if (this.#isPromiseLike(data)) {
          data.then(resolve, reject);
        } else {
          resolve(data);
        }
      } catch (error) {
        reject(error);
      }
    });
  }

  /**
   * 执行handlers
   * @returns {void} void
   */
  #run() {
    if (this.#state === PENDING) return;
    // 循环遍历
    while (this.#handlers.length) {
      const { onFulfilled, onRejected, resolve, reject } = this.#handlers.shift();
      if (this.#state === FUIFILLED) {
        this.#runOne(onFulfilled, resolve, reject);
      } else {
        this.#runOne(onRejected, resolve, reject);
      }
    }
  }

  /**
   * 主要记录#handlers、执行#run
   * @param {Function} onFulfilled 成功回调
   * @param {Function} onRejected 失败回调
   * @returns {MyPromise} 返回一个新的MyPromise
   */
  then(onFulfilled, onRejected) {
    return new MyPromise((resolve, reject) => {
      this.#handlers.push({ onFulfilled, onRejected, resolve, reject });
      this.#run();
    });
  }

  /**
   * catch实例方法
   * @param {Function} onRejected 拒绝回调
   * @returns {MyPromise} 新的MyPromise
   */
  catch(onRejected) {
    return this.then(undefined, onRejected);
  }

  /**
   * finally实例方法
   * @param {Function} onFinally 回调函数
   * @returns {MyPromise} 新的MyPromise
   */
  finally(onFinally) {
    return this.then(
      data => {
        onFinally();
        return data;
      },
      err => {
        onFinally();
        throw err;
      }
    );
  }

  /**
   * resolve静态方法
   * @param {any} value 参数值
   * @returns {MyPromise} 新的MyPromise
   */
  static resolve(value) {
    if (value instanceof MyPromise) return value;
    let _resolve, _reject;
    const p = new MyPromise((resolve, reject) => {
      _resolve = resolve;
      _reject = reject;
    });
    if (p.#isPromiseLike(value)) {
      value.then(_resolve, _reject);
    } else {
      _resolve(value);
    }
    return p;
  }

  /**
   * reject静态方法
   * @param {Function} onRejected 拒绝回调
   * @returns {MyPromise} 新的MyPromise
   */
  static reject(onRejected) {
    return new MyPromise((resolve, reject) => {
      reject(onRejected);
    });
  }

  /**
   * 判断是否是迭代器
   * @param {any} value 参数
   * @returns {boolean} boolean
   */
  #isIterator(value) {
    if (typeof value === "string") {
      return true;
    }
    if (value !== null && (typeof value === "object" || typeof value === "function")) {
      return typeof value[Symbol.iterator] === "function";
    }
    return false;
  }

  /**
   * 静态方法all
   * @param {Iterable} proms 参数
   * @returns {MyPromise} 新的MyPromise
   */
  static all(proms) {
    let _resolve, _reject;
    let count = 0,
      finishNum = 0;
    const result = [];

    const p = new MyPromise((resolve, reject) => {
      _resolve = resolve;
      _reject = reject;
    });

    if (p.#isIterator(proms)) {
      for (const prom of proms) {
        const index = count; // 获取下标
        count++;
        MyPromise.resolve(prom).then(data => {
          result[index] = data; // 将成功的值加入数组中
          finishNum++;
          if (finishNum === count) {
            // 全部完成结束
            _resolve(result);
          }
        }, _reject);
      }

      // 表示空数组
      if (count === 0) {
        _resolve([]);
      }
    } else {
      // 如果iterator不是可迭代对象，则reject
      _reject(`TypeError: ${typeof proms} ${proms} is not iterable (cannot read property Symbol(Symbol.iterator))`);
    }

    return p;
  }

  /**
   * 静态方法race
   * @param {Iterable} proms 可迭代对象
   * @returns 新的MyPromise
   */
  static race(proms) {
    let _resolve, _reject;

    const p = new MyPromise((resolve, reject) => {
      _resolve = resolve;
      _reject = reject;
    });

    // 谁先结束状态就发生变化
    if (p.#isIterator(proms)) {
      for (const prom of proms) {
        MyPromise.resolve(prom).then(_resolve, _reject);
      }
    } else {
      // 如果iterator不是可迭代对象，则reject
      _reject(`TypeError: ${typeof proms} ${proms} is not iterable (cannot read property Symbol(Symbol.iterator))`);
    }

    return p;
  }

  /**
   * 静态方法allSettled
   * @param {*} proms 可迭代对象
   * @returns 新的MyPromise
   */
  static allSettled(proms) {
    let _resolve, _reject;
    let count = 0,
      total = 0;
    const result = [];

    const p = new MyPromise((resolve, reject) => {
      _resolve = resolve;
      _reject = reject;
    });

    if (p.#isIterator(proms)) {
      for (const prom of proms) {
        const index = count;
        count++;
        MyPromise.resolve(prom)
          .then(value => {
            result[index] = {
              status: "fulfilled",
              value
            };
          })
          .catch(reason => {
            result[index] = {
              status: "rejected",
              reason
            };
          })
          .finally(() => {
            total++;
            if (total === count) {
              // 全部状态都结束
              _resolve(result);
            }
          });
      }

      // 如果可迭代对象是空的则返回空数组
      if (count === 0) {
        _resolve([]);
      }
    } else {
      // 如果iterator不是可迭代对象，则reject
      _reject(`TypeError: ${typeof proms} ${proms} is not iterable (cannot read property Symbol(Symbol.iterator))`);
    }

    return p;
  }
}

// 测试
const p = new Promise((resolve, reject) => {
  resolve(123);
});

MyPromise.race("123").then(data => {
  console.log("data ", data);
});
